home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Largest Collection of Windows Software
/
The World's Largest Collection of Windows Software - Disc 2.iso
/
textproc
/
_j1
/
tex2rtf
/
src
/
texutils.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-25
|
22KB
|
932 lines
/*
* Miscellaneous utilities for manipulating LaTeX files and constructs
*
*/
#include <wx.h>
#include <iostream.h>
#include <ctype.h>
#include "tex2any.h"
wxList TexReferences(wxKEY_STRING);
wxList BibList(wxKEY_STRING);
wxStringList CitationList;
wxList CustomMacroList(wxKEY_STRING);
// Look for \label macro, use this ref name if found or
// make up a topic name otherwise.
static long topicCounter = 0;
void ResetTopicCounter(void)
{
topicCounter = 0;
}
char *FindTopicName(TexChunk *chunk)
{
char *topicName = NULL;
static char topicBuf[100];
if (chunk && (chunk->type == CHUNK_TYPE_MACRO) &&
(strcmp(chunk->name, "label") == 0))
{
wxNode *node = chunk->children.First();
if (node)
{
TexChunk *child = (TexChunk *)node->Data();
if (child->type == CHUNK_TYPE_ARG)
{
wxNode *snode = child->children.First();
if (snode)
{
TexChunk *schunk = (TexChunk *)snode->Data();
if (schunk->type == CHUNK_TYPE_STRING)
topicName = schunk->value;
}
}
}
}
if (topicName)
return topicName;
else
{
sprintf(topicBuf, "topic%ld", topicCounter);
topicCounter ++;
return topicBuf;
}
}
/*
* Simulate argument data, so we can 'drive' clients which implement
* certain basic formatting behaviour.
* Snag is that some save a TexChunk, so don't use yet...
*
*/
void StartSimulateArgument(char *data)
{
strcpy(currentArgData, data);
haveArgData = TRUE;
}
void EndSimulateArgument(void)
{
haveArgData = FALSE;
}
/*
* Parse and convert unit arguments to points
*
*/
int ParseUnitArgument(char *unitArg)
{
float conversionFactor = 1.0;
float unitValue = 0.0;
int len = strlen(unitArg);
if (unitArg && (len > 0) && (isdigit(unitArg[0]) || unitArg[0] == '-'))
{
sscanf(unitArg, "%f", &unitValue);
if (len > 1)
{
char units[3];
units[0] = unitArg[len-1];
units[1] = unitArg[len-2];
units[2] = 0;
if (strcmp(units, "in") == 0)
conversionFactor = 72.0;
else if (strcmp(units, "cm") == 0)
conversionFactor = 72.0/2.51;
else if (strcmp(units, "mm") == 0)
conversionFactor = 72.0/25.1;
else if (strcmp(units, "pt") == 0)
conversionFactor = 1;
}
return (int)(unitValue*conversionFactor);
}
else return 0;
}
/*
* Strip off any extension (dot something) from end of file,
* IF one exists. Inserts zero into buffer.
*
*/
void StripExtension(char *buffer)
{
int len = strlen(buffer);
int i = len-1;
while (i > 0)
{
if (buffer[i] == '.')
{
buffer[i] = 0;
break;
}
i --;
}
}
/*
* Latex font setting
*
*/
void SetFontSizes(int pointSize)
{
switch (pointSize)
{
case 12:
{
normalFont = 12;
smallFont = 10;
tinyFont = 8;
largeFont1 = 14;
LargeFont2 = 16;
LARGEFont3 = 20;
hugeFont1 = 24;
HugeFont2 = 28;
HUGEFont3 = 32;
break;
}
case 11:
{
normalFont = 11;
smallFont = 9;
tinyFont = 7;
largeFont1 = 13;
LargeFont2 = 16;
LARGEFont3 = 19;
hugeFont1 = 22;
HugeFont2 = 26;
HUGEFont3 = 30;
break;
}
case 10:
{
normalFont = 10;
smallFont = 8;
tinyFont = 6;
largeFont1 = 12;
LargeFont2 = 14;
LARGEFont3 = 18;
hugeFont1 = 20;
HugeFont2 = 24;
HUGEFont3 = 28;
break;
}
}
}
/*
* Latex references
*
*/
void AddTexRef(char *name, char *file, char *sectionName,
int chapter, int section, int subsection, int subsubsection)
{
wxNode *node = TexReferences.Find(name);
if (node) delete node;
char buf[100];
buf[0] = 0;
if (sectionName)
{
strcat(buf, sectionName);
strcat(buf, " ");
}
if (chapter)
{
char buf2[10];
sprintf(buf2, "%d", chapter);
strcat(buf, buf2);
}
if (section)
{
char buf2[10];
if (chapter)
strcat(buf, ".");
sprintf(buf2, "%d", section);
strcat(buf, buf2);
}
if (subsection)
{
char buf2[10];
strcat(buf, ".");
sprintf(buf2, "%d", subsection);
strcat(buf, buf2);
}
if (subsubsection)
{
char buf2[10];
sprintf(buf2, "%d", subsubsection);
strcat(buf, buf2);
}
TexReferences.Append(name, new TexRef(name, file, (strlen(buf) > 0) ? buf : NULL));
}
void WriteTexReferences(char *filename)
{
ofstream ostr(filename);
if (ostr.bad()) return;
char buf[200];
wxNode *node = TexReferences.First();
while (node)
{
TexRef *ref = (TexRef *)node->Data();
ostr << ref->refLabel << " " << (ref->refFile ? ref->refFile : "??") << " ";
ostr << (ref->sectionNumber ? ref->sectionNumber : "??") << "\n";
if (!ref->sectionNumber || (strcmp(ref->sectionNumber, "??") == 0))
{
sprintf(buf, "Warning: reference %s not resolved.", ref->refLabel);
OnInform(buf);
}
node = node->Next();
}
}
void ReadTexReferences(char *filename)
{
ifstream istr(filename);
if (istr.bad()) return;
char label[100];
char file[400];
char section[100];
while (!istr.eof())
{
istr >> label;
if (!istr.eof())
{
istr >> file;
char ch;
istr.get(ch); // Read past space
istr.get(ch);
int i = 0;
while (ch != '\n' && !istr.eof())
{
section[i] = ch;
i ++;
istr.get(ch);
}
section[i] = 0;
TexReferences.Append(label, new TexRef(label, file, section));
}
}
}
/*
* Bibliography-handling code
*
*/
void BibEatWhiteSpace(istream& str)
{
char ch = str.peek();
while (!str.eof() && (ch == ' ' || ch == '\t' || ch == 13 || ch == 10 || ch == EOF))
{
str.get(ch);
ch = str.peek();
}
}
// Read word up to { or , or space
void BibReadWord(istream& istr, char *buffer)
{
int i = 0;
buffer[i] = 0;
char ch = istr.peek();
while (!istr.eof() && ch != ' ' && ch != '{' && ch != 13 && ch != 10 && ch != '\t' &&
ch != ',' && ch != '=')
{
istr.get(ch);
buffer[i] = ch;
i ++;
ch = istr.peek();
}
buffer[i] = 0;
}
void BibReadToEOL(istream& istr, char *buffer)
{
int i = 0;
buffer[i] = 0;
char ch = istr.peek();
while (!istr.eof() && ch != 13 && ch != 10)
{
istr.get(ch);
buffer[i] = ch;
i ++;
ch = istr.peek();
}
buffer[i] = 0;
}
// Read }-terminated value, taking nested braces into account.
void BibReadValue(istream& istr, char *buffer, Bool ignoreBraces = TRUE,
Bool quotesMayTerminate = TRUE)
{
int braceCount = 1;
int i = 0;
buffer[i] = 0;
char ch = istr.peek();
Bool stopping = FALSE;
while (!istr.eof() && !stopping)
{
istr.get(ch);
if (ch == '{')
braceCount ++;
if (ch == '}')
{
braceCount --;
if (braceCount == 0)
{
stopping = TRUE;
break;
}
}
else if (quotesMayTerminate && ch == '"')
{
stopping = TRUE;
break;
}
if (!stopping)
{
if (!ignoreBraces || (ch != '{' && ch != '}'))
{
buffer[i] = ch;
i ++;
}
}
}
buffer[i] = 0;
}
Bool ReadBib(char *filename)
{
ifstream istr(filename);
if (istr.bad()) return FALSE;
OnInform("Reading .bib file...");
char ch;
char fieldValue[2000];
char recordType[100];
char recordKey[100];
char recordField[100];
while (!istr.eof())
{
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '@')
{
OnError("Expected @: malformed .bib file.");
return FALSE;
}
BibReadWord(istr, recordType);
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '{' && ch != '(')
{
OnError("Expected { or ( after record type: malformed .bib file.");
return FALSE;
}
BibEatWhiteSpace(istr);
if (StringMatch(recordType, "string", FALSE, TRUE))
{
BibReadWord(istr, fieldValue);
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '=')
{
OnError("Expected = after string key: malformed .bib file.");
return FALSE;
}
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '"' && ch != '{')
{
OnError("Expected = after string key: malformed .bib file.");
return FALSE;
}
BibReadValue(istr, fieldValue);
BibEatWhiteSpace(istr);
}
else
{
BibReadWord(istr, recordKey);
BibEntry *bibEntry = new BibEntry;
bibEntry->key = copystring(recordKey);
bibEntry->type = copystring(recordType);
Bool moreRecords = TRUE;
while (moreRecords && !istr.eof())
{
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch == '}' || ch == ')')
{
moreRecords = FALSE;
}
else if (ch == ',')
{
BibEatWhiteSpace(istr);
BibReadWord(istr, recordField);
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '=')
{
OnError("Expected = after field type: malformed .bib file.");
return FALSE;
}
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '{' && ch != '"')
{
fieldValue[0] = ch;
BibReadWord(istr, fieldValue+1);
}
else
BibReadValue(istr, fieldValue);
// Now we can add a field
if (StringMatch(recordField, "author", FALSE, TRUE))
bibEntry->author = copystring(fieldValue);
else if (StringMatch(recordField, "key", FALSE, TRUE))
{}
else if (StringMatch(recordField, "annotate", FALSE, TRUE))
{}
else if (StringMatch(recordField, "edition", FALSE, TRUE))
{}
else if (StringMatch(recordField, "howpublished", FALSE, TRUE))
{}
else if (StringMatch(recordField, "note", FALSE, TRUE))
{}
else if (StringMatch(recordField, "series", FALSE, TRUE))
{}
else if (StringMatch(recordField, "type", FALSE, TRUE))
{}
else if (StringMatch(recordField, "editor", FALSE, TRUE))
bibEntry->editor= copystring(fieldValue);
else if (StringMatch(recordField, "title", FALSE, TRUE))
bibEntry->title= copystring(fieldValue);
else if (StringMatch(recordField, "booktitle", FALSE, TRUE))
bibEntry->booktitle= copystring(fieldValue);
else if (StringMatch(recordField, "journal", FALSE, TRUE))
bibEntry->journal= copystring(fieldValue);
else if (StringMatch(recordField, "volume", FALSE, TRUE))
bibEntry->volume= copystring(fieldValue);
else if (StringMatch(recordField, "number", FALSE, TRUE))
bibEntry->number= copystring(fieldValue);
else if (StringMatch(recordField, "year", FALSE, TRUE))
bibEntry->year= copystring(fieldValue);
else if (StringMatch(recordField, "month", FALSE, TRUE))
bibEntry->month= copystring(fieldValue);
else if (StringMatch(recordField, "pages", FALSE, TRUE))
bibEntry->pages= copystring(fieldValue);
else if (StringMatch(recordField, "publisher", FALSE, TRUE))
bibEntry->publisher= copystring(fieldValue);
else if (StringMatch(recordField, "address", FALSE, TRUE))
bibEntry->address= copystring(fieldValue);
else if (StringMatch(recordField, "institution", FALSE, TRUE) || StringMatch(recordField, "school", FALSE, TRUE))
bibEntry->institution= copystring(fieldValue);
else if (StringMatch(recordField, "organization", FALSE, TRUE))
bibEntry->organization= copystring(fieldValue);
else if (StringMatch(recordField, "comment", FALSE, TRUE))
bibEntry->comment= copystring(fieldValue);
else if (StringMatch(recordField, "chapter", FALSE, TRUE))
bibEntry->chapter= copystring(fieldValue);
else
{
char buf[200];
sprintf(buf, "Unrecognised field type %s", recordField);
OnError(buf);
}
}
BibList.Append(recordKey, bibEntry);
BibEatWhiteSpace(istr);
}
}
}
return TRUE;
}
void OutputBibItem(TexRef *ref, BibEntry *bib)
{
OnMacro("bibitem", 2, TRUE);
OnArgument("bibitem", 1, TRUE);
TexOutput(ref->sectionNumber);
OnArgument("bibitem", 1, FALSE);
OnArgument("bibitem", 2, TRUE);
TexOutput(" ");
OnMacro("bf", 1, TRUE);
OnArgument("bf", 1, TRUE);
if (bib->author)
TexOutput(bib->author);
OnArgument("bf", 1, FALSE);
OnMacro("bf", 1, FALSE);
if (bib->author && (strlen(bib->author) > 0) && (bib->author[strlen(bib->author) - 1] != '.'))
TexOutput(". ");
else
TexOutput(" ");
if (bib->year)
{
TexOutput(bib->year);
}
if (bib->month)
{
TexOutput(" (");
TexOutput(bib->month);
TexOutput(")");
}
if (bib->year || bib->month)
TexOutput(". ");
if (StringMatch(bib->type, "article", FALSE, TRUE))
{
if (bib->title)
{
TexOutput(bib->title);
TexOutput(". ");
}
if (bib->journal)
{
OnMacro("it", 1, TRUE);
OnArgument("it", 1, TRUE);
TexOutput(bib->journal);
OnArgument("it", 1, FALSE);
OnMacro("it", 1, FALSE);
}
if (bib->volume)
{
TexOutput(", ");
OnMacro("bf", 1, TRUE);
OnArgument("bf", 1, TRUE);
TexOutput(bib->volume);
OnArgument("bf", 1, FALSE);
OnMacro("bf", 1, FALSE);
}
if (bib->number)
{
TexOutput("(");
TexOutput(bib->number);
TexOutput(")");
}
if (bib->pages)
{
TexOutput(", pages ");
TexOutput(bib->pages);
}
TexOutput(".");
}
else if (StringMatch(bib->type, "book", FALSE, TRUE) ||
StringMatch(bib->type, "unpublished", FALSE, TRUE) ||
StringMatch(bib->type, "manual", FALSE, TRUE) ||
StringMatch(bib->type, "phdthesis", FALSE, TRUE) ||
StringMatch(bib->type, "mastersthesis", FALSE, TRUE) ||
StringMatch(bib->type, "misc", FALSE, TRUE) ||
StringMatch(bib->type, "techreport", FALSE, TRUE) ||
StringMatch(bib->type, "booklet", FALSE, TRUE))
{
if (bib->title || bib->booktitle)
{
OnMacro("it", 1, TRUE);
OnArgument("it", 1, TRUE);
TexOutput(bib->title ? bib->title : bib->booktitle);
TexOutput(". ");
OnArgument("it", 1, FALSE);
OnMacro("it", 1, FALSE);
}
if (StringMatch(bib->type, "phdthesis", FALSE, TRUE))
TexOutput("PhD thesis. ");
if (StringMatch(bib->type, "techreport", FALSE, TRUE))
TexOutput("Technical report. ");
if (bib->editor)
{
TexOutput("Ed. ");
TexOutput(bib->editor);
TexOutput(". ");
}
if (bib->institution)
{
TexOutput(bib->institution);
TexOutput(". ");
}
if (bib->organization)
{
TexOutput(bib->organization);
TexOutput(". ");
}
if (bib->publisher)
{
TexOutput(bib->publisher);
TexOutput(". ");
}
if (bib->address)
{
TexOutput(bib->address);
TexOutput(". ");
}
}
else if (StringMatch(bib->type, "inbook", FALSE, TRUE) ||
StringMatch(bib->type, "inproceedings", FALSE, TRUE) ||
StringMatch(bib->type, "incollection", FALSE, TRUE) ||
StringMatch(bib->type, "conference", FALSE, TRUE))
{
if (bib->title)
{
TexOutput(bib->title);
}
if (bib->booktitle)
{
TexOutput(", from ");
OnMacro("it", 1, TRUE);
OnArgument("it", 1, TRUE);
TexOutput(bib->booktitle);
TexOutput(".");
OnArgument("it", 1, FALSE);
OnMacro("it", 1, FALSE);
}
if (bib->editor)
{
TexOutput(", ed. ");
TexOutput(bib->editor);
}
if (bib->publisher)
{
TexOutput(" ");
TexOutput(bib->publisher);
}
if (bib->address)
{
if (bib->publisher) TexOutput(", ");
else TexOutput(" ");
TexOutput(bib->address);
}
if (bib->publisher || bib->address)
TexOutput(".");
if (bib->volume)
{
TexOutput(" ");
OnMacro("bf", 1, TRUE);
OnArgument("bf", 1, TRUE);
TexOutput(bib->volume);
OnArgument("bf", 1, FALSE);
OnMacro("bf", 1, FALSE);
}
if (bib->number)
{
if (bib->volume)
{
TexOutput("(");
TexOutput(bib->number);
TexOutput(").");
}
else
{
TexOutput(" Number ");
TexOutput(bib->number);
TexOutput(".");
}
}
if (bib->chapter)
{
TexOutput(" Chap. "); TexOutput(bib->chapter);
}
if (bib->pages)
{
if (bib->chapter) TexOutput(", pages ");
else TexOutput(" Pages ");
TexOutput(bib->pages);
TexOutput(".");
}
}
OnArgument("bibitem", 2, FALSE);
OnMacro("bibitem", 2, FALSE);
}
void OutputBib(void)
{
// Write the title
OnMacro("references", 0, TRUE);
OnMacro("references", 0, FALSE);
wxNode *node = CitationList.First();
while (node)
{
char *citeKey = (char *)node->Data();
wxNode *texNode = TexReferences.Find(citeKey);
wxNode *bibNode = BibList.Find(citeKey);
if (bibNode && texNode)
{
BibEntry *entry = (BibEntry *)bibNode->Data();
TexRef *ref = (TexRef *)texNode->Data();
OutputBibItem(ref, entry);
}
node = node->Next();
}
}
static int citeCount = 1;
void ResolveBibReferences(void)
{
if (CitationList.Number() > 0)
OnInform("Resolving bibliographic references...");
citeCount = 1;
char buf[200];
wxNode *node = CitationList.First();
while (node)
{
char *citeKey = (char *)node->Data();
wxNode *texNode = TexReferences.Find(citeKey);
wxNode *bibNode = BibList.Find(citeKey);
if (bibNode && texNode)
{
TexRef *ref = (TexRef *)texNode->Data();
BibEntry *entry = (BibEntry *)bibNode->Data();
if (ref->sectionNumber) delete[] ref->sectionNumber;
sprintf(buf, "[%d]", citeCount);
ref->sectionNumber = copystring(buf);
citeCount ++;
}
else
{
sprintf(buf, "Warning: bib ref %s not resolved.", citeKey);
OnInform(buf);
}
node = node->Next();
}
}
// Remember we need to resolve this citation
void AddCitation(char *citeKey)
{
if (!CitationList.Member(citeKey))
CitationList.Add(citeKey);
if (!TexReferences.Find(citeKey))
{
TexReferences.Append(citeKey, new TexRef(citeKey, "??", NULL));
}
}
/*
* Custom macro stuff
*
*/
// Define a variable value from the .ini file
void RegisterSetting(char *settingName, char *settingValue)
{
if (StringMatch(settingName, "chapterFontSize", FALSE, TRUE))
StringToInt(settingValue, &chapterFont);
else if (StringMatch(settingName, "sectionFontSize", FALSE, TRUE))
StringToInt(settingValue, §ionFont);
else if (StringMatch(settingName, "subsectionFontSize", FALSE, TRUE))
StringToInt(settingValue, &subsectionFont);
else if (StringMatch(settingName, "documentFontSize", FALSE, TRUE))
{
int n;
StringToInt(settingValue, &n);
if (n == 10 || n == 11 || n == 12)
SetFontSizes(n);
else
{
char buf[200];
sprintf(buf, "Initialisation file error: nonstandard document font size %d.", n);
OnInform(buf);
}
}
else
{
char buf[200];
sprintf(buf, "Initialisation file error: unrecognised setting %s.", settingName);
OnInform(buf);
}
}
Bool ReadCustomMacros(char *filename)
{
ifstream istr(filename);
if (istr.bad()) return FALSE;
OnInform("Reading custom macros...");
CustomMacroList.Clear();
char ch;
char macroName[100];
char macroBody[1000];
int noArgs;
while (!istr.eof())
{
BibEatWhiteSpace(istr);
istr.get(ch);
if (istr.eof())
break;
if (ch != '\\') // Not a macro definition, so must be NAME=VALUE
{
char settingName[100];
settingName[0] = ch;
BibReadWord(istr, (settingName+1));
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '=')
{
OnError("Expected = following name: malformed tex2rtf.ini file.");
return FALSE;
}
else
{
char settingValue[200];
BibEatWhiteSpace(istr);
BibReadToEOL(istr, settingValue);
RegisterSetting(settingName, settingValue);
}
}
else
{
BibReadWord(istr, macroName);
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '[')
{
OnError("Expected [ followed by number of arguments: malformed tex2rtf.ini file.");
return FALSE;
}
istr >> noArgs;
istr.get(ch);
if (ch != ']')
{
OnError("Expected ] following number of arguments: malformed tex2rtf.ini file.");
return FALSE;
}
BibEatWhiteSpace(istr);
istr.get(ch);
if (ch != '{')
{
OnError("Expected { followed by macro body: malformed tex2rtf.ini file.");
return FALSE;
}
CustomMacro *macro = new CustomMacro(macroName, noArgs, NULL);
BibReadValue(istr, macroBody, FALSE, FALSE); // Don't ignore extra braces
if (strlen(macroBody) > 0)
macro->macroBody = copystring(macroBody);
BibEatWhiteSpace(istr);
CustomMacroList.Append(macroName, macro);
AddMacroDef(macroName, noArgs);
}
}
return TRUE;
}
CustomMacro *FindCustomMacro(char *name)
{
wxNode *node = CustomMacroList.Find(name);
if (node)
{
CustomMacro *macro = (CustomMacro *)node->Data();
return macro;
}
return NULL;
}
// Display custom macros
void ShowCustomMacros(void)
{
wxNode *node = CustomMacroList.First();
if (!node)
{
OnInform("No custom macros loaded.\n");
return;
}
char buf[400];
while (node)
{
CustomMacro *macro = (CustomMacro *)node->Data();
sprintf(buf, "\\%s[%d]\n {%s}", macro->macroName, macro->noArgs,
macro->macroBody ? macro->macroBody : "");
OnInform(buf);
node = node->Next();
}
}